package cn.Y_Qiu.org.service.impl;

import cn.Y_Qiu.basic.exception.BusinessException;
import cn.Y_Qiu.basic.util.StrUtils;
import cn.Y_Qiu.user.domain.User;
import cn.Y_Qiu.user.domain.WxUser;
import cn.Y_Qiu.user.mapper.UserMapper;
import cn.Y_Qiu.user.mapper.WxUserMapper;
import com.alibaba.fastjson.JSONObject;
import cn.Y_Qiu.basic.util.Ajaxresult;
import cn.Y_Qiu.basic.util.HttpClientUtils;
import cn.Y_Qiu.org.domain.LoginDto;
import cn.Y_Qiu.org.service.ILoginService;
import cn.Y_Qiu.user.domain.LoginInfo;
import cn.Y_Qiu.user.mapper.LoginInfoMapper;
import cn.Y_Qiu.user.util.MD5Utils;
import cn.Y_Qiu.user.util.UserCodeutil;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

@Service
public class LoginServiceImpl implements ILoginService {
    @Autowired
    private LoginInfoMapper loginInfoMapper;
    @Autowired
    private WxUserMapper wxUserMapper;
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private RedisTemplate redisTemplate;

    @Override
    public Ajaxresult login(LoginDto loginDto) {
        //1 校验
        // 1.1 null判断
        if (loginDto.getUsername() == null ||
        loginDto.getPassword() == null ||
        loginDto.getType() == null
                ) {
            throw new BusinessException("账户名或密码为空");
        }
        // 1.2 判断用户是否存在 Username--username,phone,email
        LoginInfo loginInfo = loginInfoMapper.queryByLoginDto(loginDto);
        if (loginInfo == null){
            throw new BusinessException("账户不存在");
        }
        // 1.3 判断用户状态是否ok
        if (loginInfo.getDisable() != 1){
            throw new BusinessException("账号不可用");
        }
        //2 比对密码完成登录
        String password = loginInfo.getPassword();
        String loginDtoPassword = loginDto.getPassword();
        String loginInfoSalt = loginInfo.getSalt();
        String dtospassword = MD5Utils.encrypByMd5(loginInfoSalt + loginDtoPassword);
        if (!dtospassword.equals(password)){
            throw new BusinessException("账号或密码错误");
        }
        //3 记录logininfo到redis，key是token
        String token = UUID.randomUUID().toString();
        redisTemplate.opsForValue().set(token, loginInfo,30, TimeUnit.MINUTES);
        //4 返回AjaxResult，如果登录成功，还需要返回token和loginInfo
        //为了安全起见，把前台不会用到关键信息salt和password去空
        Map map = new HashMap<>();
        loginInfo.setSalt(null);
        loginInfo.setPassword(null);
        map.put("token", token);
        map.put("loginInfo", loginInfo);
        return Ajaxresult.me().setResultObj(map);
    }

    @Override
    public Ajaxresult wechat(Map<String, String> params) {
//        2.后端接口收到请求，交给service处理
//        3.service业务流
//        4.code不能为空
        String code = params.get("code");
        if (code == null){
            throw new BusinessException("code为空");
        }
        //System.out.println(params.get("code")); 有code
//        5.根据code从微信获取token  使用httpClient         ②
        //此处url应为此格式
        /*https://api.weixin.qq.com/sns/oauth2/access_token?
                 appid=APPID
                &secret=SECRET
                &code=CODE
                &grant_type=authorization_code
         */
        String tokenurl = UserCodeutil.WXUSER_GET_TOKEN_URL
                .replace("APPID", UserCodeutil.APPID)
                .replace("SECRET", UserCodeutil.SECRET)
                .replace("CODE", code);
//        6.拿到token+openId
        String tokenurlget = HttpClientUtils.httpGet(tokenurl);
        JSONObject jsonObject = JSONObject.parseObject(tokenurlget);
        String accessToken = jsonObject.getString("access_token");
        String openid = jsonObject.getString("openid");
//        7.判断openId是已经存在（查询t_wxUser），
        LoginInfo loginInfo  = new LoginInfo();
        WxUser wxUserByopenid = wxUserMapper.queryByOpenId(openid);
        if (wxUserByopenid !=null){
//        7.1.如果已经有了并且userid不为空，直接免密登录
            loginInfo = loginInfoMapper.queryByUserId(wxUserByopenid.getUser_id());
            String token = UUID.randomUUID().toString();
            redisTemplate.opsForValue().set(token, loginInfo,30, TimeUnit.MINUTES);
            //返回AjaxResult，如果登录成功，还需要返回token和loginInfo
            //为了安全起见，把前台不会用到关键信息salt和password去空
            Map map = new HashMap<>();
            loginInfo.setSalt(null);
            loginInfo.setPassword(null);
            map.put("token", token);
            map.put("loginInfo", loginInfo);
            System.out.println("有账号，登录成功");
            return Ajaxresult.me().setResultObj(map);
        }
//        7.2 如果为空，需要让用户绑定个人用户信息
//        返回token+openId 前端帮我们跳转到绑定页面
        // 此处需要返回的是字符串，因为前端跳转为url+result.resultobj
        String binderurl = "?accessToken=" + accessToken + "&openId=" + openid;
        return Ajaxresult.me().setSuccess(false).setResultObj(binderurl);
    }

    //二：微信绑定流程
    //1.在callback.html页面的钩子函数中
    //2.接收微信登录流程的返回值：
    //AjaxResult {success:false,resultObj:"?token=asdfaf$openId=136462315546"}
    //3.跳转到binder.html页面
    //location.href="binder.html"+resultObj;
    //4.binder.html页面解析地址栏参数并且接收用户输入的参数
    //5.发起微信绑定流程
    //phone  verifyCode   token    openId
    //6.后端接收参数交给service处理
    @Override
    public Ajaxresult binder(Map<String, String> params) {
        //7.service业务流
        //一：校验
        //1.空校验
        //2.判断验证码
        String phone = params.get("phone");
        String verifyCode = params.get("verifyCode");
        String accessToken = params.get("accessToken");
        String openId = params.get("openId");
        if (!StringUtils.hasLength(phone) ||
            !StringUtils.hasLength(verifyCode) ||
            !StringUtils.hasLength(accessToken)  ||
            !StringUtils.hasLength(openId)
                ){
            throw new BusinessException("必要信息为空");
        }
        Object codetmp = redisTemplate.opsForValue().get(UserCodeutil.BUSINESS_BINDER_PREFIX + phone);
        if (codetmp == null) {
            throw new BusinessException("验证码已过期");
        }
        //二：判断phone是否被注册 user
        User userbyphone = userMapper.queryByPhone(phone);
        User user = null;
        LoginInfo loginInfo = null;
        if (userbyphone != null){
            //1.如果注册了，那么我们可以直接绑定微信用户了
            user = userbyphone;
            loginInfo = loginInfoMapper.queryByUserId(user.getLogininfo_id());
        } else {
            //2.如果没有注册过，生成t_user + t_loginInfo

            user = initUser(phone);
            loginInfo = user2LoginInfo(user);
            //loginInfo.setDisable();
            loginInfoMapper.add(loginInfo);
            user.setLogininfo_id(loginInfo.getId());
            userMapper.add(user);
        }
        //三：通过 token+openId 查询微信信息 wxuser         ③
        String tokenurl = UserCodeutil.WXUSER_GET_USER_URL
                .replace("ACCESS_TOKEN", accessToken)
                .replace("OPENID", openId);

        String httpGet = HttpClientUtils.httpGet(tokenurl);
        //生成t_wxuser
        WxUser wxUser = initWxUser(httpGet,user);
        wxUserMapper.add(wxUser);
        //四：绑定user和wxuser
        //五：免密登录
        String token = UUID.randomUUID().toString();
        redisTemplate.opsForValue().set(token, loginInfo,30, TimeUnit.MINUTES);
        //返回AjaxResult，如果登录成功，还需要返回token和loginInfo
        //为了安全起见，把前台不会用到关键信息salt和password去空
        Map map = new HashMap<>();
        loginInfo.setSalt(null);
        loginInfo.setPassword(null);
        map.put("token", token);
        map.put("loginInfo", loginInfo);
        System.out.println("有账号，登录成功");
        return Ajaxresult.me().setResultObj(map);
    }

    private WxUser initWxUser(String httpGet, User user) {
        JSONObject jsonObject = JSONObject.parseObject(httpGet);
    /*         ==================
                User>>>>>>>>
                username;
                email;
                phone;
                salt;
                password;
                state;
                age;
                createtime = new Date();
                headImg;
                logininfo_id;
                private String openid;
                ===================
                WxUser>>>>>>>>>>>>>
                nickname;
                sex;
                address;
                headimgurl;
                unionid;
                user_id;
        */
        WxUser wxUser = new WxUser();
        wxUser.setUser_id(user.getId());
        wxUser.setOpenid(jsonObject.getString("openid"));
        wxUser.setNickname(jsonObject.getString("nickname"));
        wxUser.setAddress(null);
        wxUser.setSex(jsonObject.getInteger("sex"));
        wxUser.setUnionid(jsonObject.getString("unionid"));
        wxUser.setHeadimgurl(jsonObject.getString("headimgurl"));
        return wxUser;
    }

    private LoginInfo user2LoginInfo(User user) {
        LoginInfo loginInfo = new LoginInfo();
        BeanUtils.copyProperties(user, loginInfo);
        // 设置为用户type
        loginInfo.setType(1);
        return loginInfo;
    }

    private User initUser(String phone) {
        User user = new User();
        user.setPhone(phone);
        user.setUsername(phone);
        String salt = StrUtils.getRandomString(32);
        // 先写死密码为1，之后发送短信通知
        String password = MD5Utils.encrypByMd5(salt + "1");
        user.setSalt(salt);
        user.setPassword(password);
        return user;
    }


}
